flowchart LR A([Run Fuseki]) --> B([Query Data]) B --> C((Tidy Data)) C --> D([Tree: WP]) C --> E([Tree: Configuration]) C --> F([Table: Mass Property]) D --> G([Decomposition Tree]) E --> G G --> H([Roll up Calculations]) F --> H H --> I([Report])
1 Workflow
?@sec-introduction
[1] "/Users/mlab/Workspaces/github/open-source-rover/"
1.1 Reusable function to Visualize Tree
Code
# I want to plot graph as dendrogram. graph doesnt have NA root for plotCollapsibleTreeFromDataframe
plotGraph2Dendrogram <- function(g){
# find root nodes
root_wp <- which(degree(g, mode = "in") == 0)
root_wp <- names(root_wp)
# Add NA
# g <- add_vertices(g, 1, name="NA")
# g <- add_edges(g, c("NA", root_wp))
df <- igraph::as_data_frame(g, what = "edges") %>%
add_row(from=NA, to=root_wp)
g2 <- graph_from_data_frame(df,
directed = TRUE,
vertices = NULL)
df_deg <- data.frame(
name = names(degree(g2)),
degree = degree(g2),
distance = distances(g2)["NA",]
)
df_g <- df %>%
left_join(df_deg, by=c("to"="name"))
p<-plotCollapsibleTreeFromDataframe(df_g, palette="BluYl", parent="from", child="to",type="distance")
return(p)
}2 Run Fuseki
2.1 Build and Run a Fuseki SPARQL endpoint for oml model query
Code
library(omlhashiR)
## oml_repository <- "../open-source-rover/"
oml_repository <- omlrepo
# omlhashiR::oml_refresh()
# omlhashiR::oml_stop_Daemon(oml_repository)
# omlhashiR::oml_build(oml_repository)
# omlhashiR::oml_startFuseki(oml_repository)
# omlhashiR::oml_owlLoad(oml_repository)3 Query Data
Code
library(tansakusuR)
endpoint_url <- "http://localhost:3030/open-source-rover/sparql"
repo <- paste0(omlrepo, "src/vision/sparql/")3.1 Tree: Configuration
Code
### <TBD> Analysis: Read Current Mass Property Data in Model
#order <- dfs(g, V(g)[root], order.out = TRUE)$order
file <- "node_systemassemblymass.sparql"
filepath <- paste0(repo,file)
#show_query(filepath)
df_mass <- send_query_from_file(endpoint_url, filepath) %>%
mutate(mass = replace_na(as.numeric(m),0))
df_configuration <- df_mass %>%
select(parent, id, name, type, mass, iri, owner)
df_mass2 <- df_configuration3.2 Visualize Configuration
This might be generated by model query directly. Because we use system-subsystem-assembly configurations now, we produce this dataframe manually.
Code
df_config<- df_configuration %>%
mutate(container="OSR") %>%
mutate(name=paste0(parent)) %>%
mutate(edgetype=paste0("contains")) %>%
select("container","name","type") %>%
filter(container != name)
#df_config$owner[df_config$name == "OSR"] <- NA
g2 <- graph_from_data_frame(df_config,
directed = TRUE,
vertices = NULL)
plot(g2, layout=layout_as_tree)Code
plotGraph2Dendrogram(g2)3.4 WP
Code
df2<- df_wp %>%
mutate(owner=paste0(parent)) %>%
mutate(name=paste0(child)) %>%
mutate(type=paste0("authorizes")) %>%
select("owner","name","type")
g2 <- graph_from_data_frame(df2,
directed = TRUE,
vertices = NULL)
# plotGraph2Dendrogram(g2)
plot(g2, layout=layout_as_tree)3.5 WP Supplies Components
Code
df_sc <- df_mass %>%
select(parent, id, name, type, mass, iri, owner) %>%
mutate(child = parent) %>%
mutate(parent = owner) %>%
mutate(childiri = iri) %>%
mutate(edgetype = "supplies") %>%
select(parent, child, edgetype)3.6 Analysis: Create Containment Graph
Code
root <- "OSR"
df_wp <- df_wp %>%
mutate(edgetype = "authorizes") %>%
select(parent, child, edgetype)
df <- rbind(df_wp, df_sc)
# swap parent and child of root
index <- which(df$child==root)
c<-df$child[index]
p<-df$parent[index]
df$child[index]<-p
df$parent[index]<-c
g <- graph_from_data_frame(df[,c("parent","child")],
directed = TRUE,
vertices = NULL)
plot(g, layout=layout_as_tree)3.7 Tree: WP supplies Component
Code
file <- "edge_suppliedComponents.sparql"
filepath <- paste0(repo,file)
#show_query(filepath)
df_c <- send_query_from_file(endpoint_url, filepath)
# datatable(df_c, options = list(pageLength = -1))
df_c# A tibble: 11 × 4
parent child componentType iri
<chr> <chr> <chr> <chr>
1 wp-body-assembly body-assembly http://imce.… http…
2 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
3 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
4 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
5 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
6 wp-drive-wheel-assembly drive-wheel-assembly… http://imce.… http…
7 wp-drive-wheel-assembly drive-wheel-assembly… http://imce.… http…
8 wp-mechanical-harness mechanical-harness http://imce.… http…
9 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
10 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
11 wp-system OSR http://imce.… http…
ここまではOK。ただしサブシステムの情報を組み込んだMELのテンプレを新たに用意する必要がある。 マスロールアップは、サブシステムを含むgraphデータを探索することになるので、グラフデータを起点にした方が良いかもしれない。 例えば、あるコンフィグレーションの node_systemassemblymass.sparql を実行する。 これとワークパッケージを対応づける必要がある。
Code
order <- dfs(g, V(g)[root], order.out = TRUE)$order
df_mel <- igraph::as_data_frame(g, what = "vertices") %>%
arrange(factor(name, levels = names(order)))
df_mel2 <- left_join(df_mel, df_mass2, by = c("name"="parent"))この処理の問題点は、owner情報が失われている点である。
- edge_workpackage.sparql
- edge_suppliedComponents.sparql
- node_systemassemblymass.sparql
様々なコンフィグレーションに対応するためにも、 System -> Assemblyのコンフィグレーションを取り出す必要がある。 現状は、node_systemassemblymass.sparql の処理がそれに該当する。
Code
df_wp# A tibble: 11 × 3
parent child edgetype
<chr> <chr> <chr>
1 wp-system wp-CDHSubsystem authorizes
2 wp-system wp-ControlSubsystem authorizes
3 wp-system wp-MechanicalSubsystem authorizes
4 wp-system wp-MobilitySubsystem authorizes
5 wp-system wp-NavigationSubsystem authorizes
6 wp-system wp-PowerSubsystem authorizes
7 wp-MechanicalSubsystem wp-body-assembly authorizes
8 wp-MobilitySubsystem wp-corner-wheel-assembly authorizes
9 wp-MobilitySubsystem wp-drive-wheel-assembly authorizes
10 wp-MechanicalSubsystem wp-mechanical-harness authorizes
11 wp-MechanicalSubsystem wp-rocker-bogie-suspension-assembly authorizes
Code
df_c# A tibble: 11 × 4
parent child componentType iri
<chr> <chr> <chr> <chr>
1 wp-body-assembly body-assembly http://imce.… http…
2 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
3 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
4 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
5 wp-corner-wheel-assembly corner-wheel-assembl… http://imce.… http…
6 wp-drive-wheel-assembly drive-wheel-assembly… http://imce.… http…
7 wp-drive-wheel-assembly drive-wheel-assembly… http://imce.… http…
8 wp-mechanical-harness mechanical-harness http://imce.… http…
9 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
10 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
11 wp-system OSR http://imce.… http…
Code
df_mass# A tibble: 11 × 8
parent id name m type owner iri mass
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 body-assembly A.01 Body … 30.0 Asse… wp-b… http… 30
2 drive-wheel-assembly-1 A.02 Drive… 15.0 Asse… wp-d… http… 15
3 drive-wheel-assembly-2 A.03 Drive… 15.0 Asse… wp-d… http… 15
4 corner-wheel-assembly-1 A.04 Corne… 25.0 Asse… wp-c… http… 25
5 corner-wheel-assembly-2 A.05 Corne… 25.0 Asse… wp-c… http… 25
6 corner-wheel-assembly-3 A.06 Corne… 25.0 Asse… wp-c… http… 25
7 corner-wheel-assembly-4 A.07 Corne… 25.0 Asse… wp-c… http… 25
8 rocker-bogie-suspension-assembly-1 A.08 Rocke… 40.0 Asse… wp-r… http… 40
9 rocker-bogie-suspension-assembly-2 A.09 Rocke… 40.0 Asse… wp-r… http… 40
10 mechanical-harness A.10 Mecha… 50.0 Asse… wp-m… http… 50
11 OSR C.01 Rover… 1640… Syst… wp-s… http… 1640
3.8 wp tree + “wp supplies components”
Code
df_wp_2<- df_wp %>%
mutate(owner=paste0(parent)) %>%
mutate(name=paste0(child)) %>%
mutate(type=paste0("authorizes")) %>%
select("owner","name","type")
df_c_2<- df_c %>%
mutate(owner=paste0(parent)) %>%
mutate(name=paste0(child)) %>%
mutate(type=paste0("supplies")) %>%
select("owner","name","type")
df2<- rbind(df_wp_2, df_c_2)
df_g <- df2
# df_g <- df2 %>%
# add_row(owner=NA, name="wp-system", type="root")
#
# df2<- rbind(df_wp, df_c) %>%
# mutate(owner=paste0(parent)) %>%
# mutate(name=paste0(child)) %>%
# mutate(type=paste0("Component")) %>%
# select("owner","name","type") %>%
# add_row(owner=NA, name="wp-system", type="root")
g2 <- graph_from_data_frame(df_g,
directed = TRUE,
vertices = NULL)
plot(g2, layout=layout_as_tree)Code
plotGraph2Dendrogram(g2)4 Analysis: Decomposition Tree
Set a “System” as a root node of the tree. Remove a node of “system isSuppliedBy Work Package”
Code
# find root nodes
root_wp <- which(degree(g2, mode = "in") == 0)
root_wp <- names(root_wp)
root_nodes <- df_mass$parent[df_mass$owner == root_wp]
# Replace root_wp as root_nodes
df2[df2 == root_wp] <- root_nodes
# Remove node
df2 <- df2 %>%
filter(owner != name)
#df2$owner[df2$name == root_nodes] <- NA
g3 <- graph_from_data_frame(df2,
directed = TRUE,
vertices = NULL)
plot(g3, layout=layout_as_tree)Code
plotGraph2Dendrogram(g3)5 Currently below subsystems miss assemblies with mass data
Code
order <- dfs(g3, V(g3)[root], order.out = TRUE)$order
df_mel <- igraph::as_data_frame(g3, what = "vertices") %>%
arrange(factor(name, levels = names(order)))%>%
filter(name !="NA")
df_mel2 <- left_join(df_mel, df_mass2, by = c("name"="parent"))Code
df_mel2$mass[df_mel2$name=="wp-CDHSubsystem"] <- 100.0
df_mel2$mass[df_mel2$name=="wp-ControlSubsystem"] <- 200.0
df_mel2$mass[df_mel2$name=="wp-NavigationSubsystem"] <- 300.0
df_mel2$mass[df_mel2$name=="wp-PowerSubsystem"] <- 400.0Code
namekey="name"
masskey="mass"
df_mass_update <- massRollUp(g3, root, df_mel2, namekey = "name",masskey = "mass")Code
df_table <- df_mass_update %>%
select(name, mass) %>%
left_join(select(df_g, name, owner, type), by=c("name"="name"))
df_table$owner[1] <- df_table$name[1]Code
library(reactable)
reactable(df_table, groupBy = "owner")6 Update Mass Properties using Json
This process includes user interface of the VS-Code Extension.
7 Read Mass Properties from data
Code
#path = "./data_massproperty.json"
#path = "./quarto_docs/chapters/04_massrollup/data_massproperty.json"
# path <- searchDirectory(4, "data_massproperty.json", dirname(getwd()))
# df_json <- read_json(path = path, simplifyVector = TRUE)8 Analysis: Mass Rollup By Depth-First Traversal
Code
# df_mass_update <- massRollUp(g, root, df_json)9 Compare: Current OML Descriptions vs JSON
Code
# df_mass_compare <- left_join(df_mass_update, df_mass, by = c("c1_localname","c1_id","c1_name","c1_type"), suffix = c("", "_before"))
# df_mass_compare10 Generate OML Descriptions
10.1 Create Instance
Code
# df_instance <- data.frame(
# name = df_mass_update$c1_localname,
# instancename = paste0(df_mass_update$c1_localname,".mass.magnitude"),
# mass = df_mass_update$c1_mass,
# type = str_replace_all(df_mass_update$c1_type, c("System"="subsystems", "Subsystem"="subsystems", "Assembly"="assembly"))
# ) 10.2 Generate OML Mass Descriptions
Code
# outputdir <- paste0(omlrepo,"src/oml/opencaesar.io/open-source-rover/description/mass/")
# outputfile <- paste0(outputdir, "masses.oml")
# omldescriptions <- generateOmlMassDescriptions(df_instance)10.3 Generate OML File
Code
# cat(file=outputfile, omldescriptions)11 Update Json
Code
# write_json(df_mass_update, path = path, pretty=TRUE)Code
# df2<- df %>%
# mutate(c2_mass = df$c1_mass[match(unlist(df$c2_localname), df$c1_localname)]) %>%
# mutate(owner=paste0(c2_localname," (", c2_mass," kg)")) %>%
# mutate(name=paste0(c1_localname," (", c1_mass," kg)")) %>%
# select("owner","name","c1_type")
#
# # Set NA node for CollapsibleTree
# df2$owner[df2$owner=="NA (NA kg)"] <- NA
#
#
# plotCollapsibleTreeFromDataframe(df2, palette="BluYl", parent="owner", child="name",type="c1_type")11.1 Some visualization experiments
networkD3::simpleNetwork
Code
# df2<- df %>%
# mutate(owner=parent) %>%
# mutate(name=child) %>%
# select("owner","name") %>%
# arrange(desc(owner))
#
#
# library(networkD3)
#
# networkD3::simpleNetwork(df2)